const events = {
  load: 'load',
  error: 'error',
}
const pageMode = {
  add: 'add',
  replace: 'replace',
}

const attrs = [
  'pageCurrent',
  'pageSize',
  'collection',
  'action',
  'field',
  'getcount',
  'orderby',
  'where',
]

export default {
  data() {
    return {
      loading: false,
      listData: this.getone ? {} : [],
      paginationInternal: {
        current: this.pageCurrent,
        size: this.pageSize,
        count: 0,
      },
      errorMessage: '',
    }
  },
  created() {
    let db = null
    let dbCmd = null

    if (this.collection) {
      this.db = uniCloud.database()
      this.dbCmd = this.db.command
    }

    this._isEnded = false

    this.$watch(
      () => {
        let al = []
        attrs.forEach((key) => {
          al.push(this[key])
        })
        return al
      },
      (newValue, oldValue) => {
        this.paginationInternal.pageSize = this.pageSize

        let needReset = false
        for (let i = 2; i < newValue.length; i++) {
          if (newValue[i] != oldValue[i]) {
            needReset = true
            break
          }
        }
        if (needReset) {
          this.clear()
          this.reset()
        }
        if (newValue[0] != oldValue[0]) {
          this.paginationInternal.current = this.pageCurrent
        }

        this._execLoadData()
      },
    )

    // #ifdef H5
    if (process.env.NODE_ENV === 'development') {
      this._debugDataList = []
      if (!window.unidev) {
        window.unidev = {
          clientDB: {
            data: [],
          },
        }
      }
      unidev.clientDB.data.push(this._debugDataList)
    }
    // #endif

    // #ifdef MP-TOUTIAO
    let changeName
    let events = this.$scope.dataset.eventOpts
    for (let i = 0; i < events.length; i++) {
      let event = events[i]
      if (event[0].includes('^load')) {
        changeName = event[1][0][0]
      }
    }
    if (changeName) {
      let parent = this.$parent
      let maxDepth = 16
      this._changeDataFunction = null
      while (parent && maxDepth > 0) {
        let fun = parent[changeName]
        if (fun && typeof fun === 'function') {
          this._changeDataFunction = fun
          maxDepth = 0
          break
        }
        parent = parent.$parent
        maxDepth--
      }
    }
    // #endif

    // if (!this.manual) {
    // 	this.loadData()
    // }
  },
  // #ifdef H5
  beforeDestroy() {
    if (process.env.NODE_ENV === 'development' && window.unidev) {
      let cd = this._debugDataList
      let dl = unidev.clientDB.data
      for (let i = dl.length - 1; i >= 0; i--) {
        if (dl[i] === cd) {
          dl.splice(i, 1)
          break
        }
      }
    }
  },
  // #endif
  methods: {
    loadData(args1, args2) {
      let callback = null
      if (typeof args1 === 'object') {
        if (args1.clear) {
          this.clear()
          this.reset()
        }
        if (args1.current !== undefined) {
          this.paginationInternal.current = args1.current
        }
        if (typeof args2 === 'function') {
          callback = args2
        }
      } else if (typeof args1 === 'function') {
        callback = args1
      }

      this._execLoadData(callback)
    },
    loadMore() {
      if (this._isEnded) {
        return
      }
      this._execLoadData()
    },
    refresh() {
      this.clear()
      this._execLoadData()
    },
    clear() {
      this._isEnded = false
      this.listData = []
    },
    reset() {
      this.paginationInternal.current = 1
    },
    remove(id, { action, callback, confirmTitle, confirmContent } = {}) {
      if (!id || !id.length) {
        return
      }
      uni.showModal({
        title: confirmTitle || '提示',
        content: confirmContent || '是否删除该数据',
        showCancel: true,
        success: (res) => {
          if (!res.confirm) {
            return
          }
          this._execRemove(id, action, callback)
        },
      })
    },
    _execLoadData(callback) {
      if (this.loading) {
        return
      }
      this.loading = true
      this.errorMessage = ''

      this._getExec()
        .then((res) => {
          this.loading = false
          const { data, count } = res.result
          this._isEnded = data.length < this.pageSize

          callback && callback(data, this._isEnded)
          this._dispatchEvent(events.load, data)

          if (this.getone) {
            this.listData = data.length ? data[0] : undefined
          } else if (this.pageData === pageMode.add) {
            this.listData.push(...data)
            if (this.listData.length) {
              this.paginationInternal.current++
            }
          } else if (this.pageData === pageMode.replace) {
            this.listData = data
            this.paginationInternal.count = count
          }

          // #ifdef H5
          if (process.env.NODE_ENV === 'development') {
            this._debugDataList.length = 0
            this._debugDataList.push(...JSON.parse(JSON.stringify(this.listData)))
          }
          // #endif
        })
        .catch((err) => {
          this.loading = false
          this.errorMessage = err
          callback && callback()
          this.$emit(events.error, err)
        })
    },
    _getExec() {
      let exec = this.db
      if (this.action) {
        exec = exec.action(this.action)
      }

      exec = exec.collection(this.collection)

      if (!(!this.where || !Object.keys(this.where).length)) {
        exec = exec.where(this.where)
      }
      if (this.field) {
        exec = exec.field(this.field)
      }
      if (this.orderby) {
        exec = exec.orderBy(this.orderby)
      }

      const { current, size } = this.paginationInternal
      exec = exec
        .skip(size * (current - 1))
        .limit(size)
        .get({
          getCount: this.getcount,
        })

      return exec
    },
    _execRemove(id, action, callback) {
      if (!this.collection || !id) {
        return
      }

      const ids = Array.isArray(id) ? id : [id]
      if (!ids.length) {
        return
      }

      uni.showLoading({
        mask: true,
      })

      let exec = this.db
      if (action) {
        exec = exec.action(action)
      }

      exec
        .collection(this.collection)
        .where({
          _id: dbCmd.in(ids),
        })
        .remove()
        .then((res) => {
          callback && callback(res.result)
          if (this.pageData === pageMode.replace) {
            this.refresh()
          } else {
            this.removeData(ids)
          }
        })
        .catch((err) => {
          uni.showModal({
            content: err.message,
            showCancel: false,
          })
        })
        .finally(() => {
          uni.hideLoading()
        })
    },
    removeData(ids) {
      let il = ids.slice(0)
      let dl = this.listData
      for (let i = dl.length - 1; i >= 0; i--) {
        let index = il.indexOf(dl[i]._id)
        if (index >= 0) {
          dl.splice(i, 1)
          il.splice(index, 1)
        }
      }
    },
    _dispatchEvent(type, data) {
      if (this._changeDataFunction) {
        this._changeDataFunction(data, this._isEnded)
      } else {
        this.$emit(type, data, this._isEnded)
      }
    },
  },
}
